package com.nfcprogram.handover;

import com.nfcprogram.device.enums.Network;
import com.nfcprogram.exception.NfcProgramException;
import com.nfcprogram.handover.resolver.HandoverResolver;

import android.bluetooth.BluetoothAdapter;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.TrafficStats;
import android.net.wifi.WifiManager;
import android.os.BatteryManager;
import android.os.Binder;
import android.util.Log;


public class DeviceMonitor {
	
	private static final String DEVICE_MONITOR = "DeviceMonitor";
	public static final boolean D = false;
	
	private final Context context;
	private BroadcastReceiver batteryLevelReceiver;
	private Thread monitorThread;
	
	
	public DeviceMonitor(Context context) {
		this.context = context;
		registerBatteryLevelReceiver();
		iniciarThreadMonitor();
	}
	
	private void setBatteryCharging(boolean batteryCharging) {
		if(batteryCharging)
			if(D) Log.v(DEVICE_MONITOR, "! Power Connected. Charging");
		else if(D) Log.v(DEVICE_MONITOR, "! Power Disconnected. Not Charging");
		ContextAwareManager.getInstance().setBatteryCharging(batteryCharging);
	}

	
	private void setBatteryLevel(int batteryLevel) {
		if(D) Log.v(DEVICE_MONITOR, "! New Battery level = " + batteryLevel + "%");
		ContextAwareManager.getInstance().setBatteryLevel(batteryLevel);
	}
	
	private void setBluetoothAdapterEnabled(){
		BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
		ContextAwareManager.getInstance().setBluetoothAdapterEnabled(mBluetoothAdapter.isEnabled());
	}
	
	private void setWifiAdapterEnabled(){
		WifiManager wm = (WifiManager)context.getSystemService(Context.WIFI_SERVICE);
		ContextAwareManager.getInstance().setWiFiAdapterEnabled(wm.isWifiEnabled());
	}

	
	private void setWiFiRSS(){
		WifiManager wm = (WifiManager)context.getSystemService(Context.WIFI_SERVICE);
		if(wm.isWifiEnabled() && wm.getConnectionInfo().getNetworkId() != -1){
			int signalLevel = WifiManager.calculateSignalLevel(wm.getConnectionInfo().getRssi(), 100);
			if(D) Log.v(DEVICE_MONITOR, "! Signal level = " + signalLevel + "%");
			ContextAwareManager.getInstance().setSignalLevel(signalLevel);
		}
	}
	
	
	private void setWiFiLinkSpeed(){
		WifiManager wm = (WifiManager)context.getSystemService(Context.WIFI_SERVICE);
		if(wm.isWifiEnabled() && wm.getConnectionInfo().getNetworkId() != -1){
			int linkSpeed = wm.getConnectionInfo().getLinkSpeed();
			if(D) Log.v(DEVICE_MONITOR, "! Link Speed= " + linkSpeed + " Mbps");
			ContextAwareManager.getInstance().setLinkSpeed(linkSpeed);
		}
	}
	
	private void updateHandoverCosts(double bluetoothCost, double wifiCost){
		ContextAwareManager instance = ContextAwareManager.getInstance();
		instance.setBluetoothHandoverCost(bluetoothCost);
		instance.setWifiHandoverCost(wifiCost);
		instance.handOverIfItIsNeeded();
	}
	
	
	private void updateRates() throws InterruptedException{
		int uid = Binder.getCallingUid(); 
		int sleepTime = 5;// seconds
		long recvB4 = TrafficStats.getUidRxBytes(uid);
	    long sentB4 = TrafficStats.getUidTxBytes(uid); 

	    Thread.sleep(sleepTime*1000);
        
        long recv = TrafficStats.getUidRxBytes(uid); // number of bytes received through the network for this UID
	    long sent = TrafficStats.getUidTxBytes(uid); // number of bytes sent through the network for this UID
	    
	    long bytesReceivedPerSecond = (recv - recvB4)/sleepTime;
	    long bytesSentPerSecond = (sent - sentB4)/sleepTime;
	    ContextAwareManager.getInstance().setIncomingRate(bytesReceivedPerSecond);
	    ContextAwareManager.getInstance().setOutcomingRate(bytesSentPerSecond);
	    
	    String uidName = context.getPackageManager().getNameForUid(uid).split(":")[0];
        //if(D) Log.d(DEVICE_MONITOR, "!! uid= "+ uid + "  uidName=" +uidName);
	    
	    if(D) Log.d(DEVICE_MONITOR, "! Number of bytes sent     tx= " + sentB4 + "/ Number of bytes received rx= " + recvB4);
	    if(D) Log.d(DEVICE_MONITOR, "! Incoming throughput= " + bytesReceivedPerSecond + " bytes/sec" + "/ Outcoming throughput= " + bytesSentPerSecond + " bytes/sec");
	    
	}
	
	
	public void registerBatteryLevelReceiver(){
		batteryLevelReceiver = new BroadcastReceiver() {
			public void onReceive(Context context, Intent intent) {
	        	//Log.d(DEVICE_MONITOR, "! batteryLevel changed intent.getAction()= " + intent.getAction());
	        	if (intent.getAction().equals(Intent.ACTION_POWER_CONNECTED)) {
	        		setBatteryCharging(true);
	        	}else if (intent.getAction().equals(Intent.ACTION_POWER_DISCONNECTED)) {
	        		setBatteryCharging(false);
	        	}else if (intent.getAction().equals(Intent.ACTION_BATTERY_CHANGED)) {
		            int rawlevel = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1);
	                int scale = intent.getIntExtra(BatteryManager.EXTRA_SCALE, -1);
		            int level = -1;
		            if (rawlevel >= 0 && scale > 0) {
		                level = (rawlevel * 100) / scale; /* This is your battery level */ 
		            }
		            setBatteryLevel(level);
		            //Toast.makeText(DeviceMonitor.this.context, "Battery Level Remaining: " + level + "%", Toast.LENGTH_LONG);
	        	}
	         }
	    };
	    context.registerReceiver(batteryLevelReceiver, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
	    context.registerReceiver(batteryLevelReceiver, new IntentFilter(Intent.ACTION_POWER_CONNECTED));
	    context.registerReceiver(batteryLevelReceiver, new IntentFilter(Intent.ACTION_POWER_DISCONNECTED));
	}
	
	
	@Override
	protected void finalize() throws Throwable {
		super.finalize();
		context.unregisterReceiver(batteryLevelReceiver);
	}
	
	public void iniciarThreadMonitor()  {
		if(monitorThread == null){
			monitorThread = new MonitorThread();
			monitorThread.start();
		}
	}

	
	private class MonitorThread extends Thread{
         @Override
         public void run() {
             while (true) {
                 try {
                	 Thread.sleep(10 * 1000);
                	// setWifiAdapterEnabled();
                	 //setBluetoothAdapterEnabled();
                	 //setWiFiRSS();
                	 setWiFiLinkSpeed();
					 updateHandoverCosts(HandoverResolver.getInstance().getCostForNetwork(Network.Bluetooth,false), HandoverResolver.getInstance().getCostForNetwork(Network.WiFi,false));
                	 updateRates();
                 } catch (InterruptedException e) {
                     e.printStackTrace();
                 } catch (NfcProgramException e) {
					e.printStackTrace();
				}
             }
         }
		
	}
	

}
